package router

import (
	"gitee.com/xinshortlink/api/xinshortlink/v1/account"
	"gitee.com/xinshortlink/api/xinshortlink/v1/group"
	"gitee.com/xinshortlink/api/xinshortlink/v1/link"
	"gitee.com/xinshortlink/internal/dto/resp"
	"gitee.com/xinshortlink/internal/dto/resp/bizerr"
	"gitee.com/xinshortlink/internal/pkg/conf"
	"gitee.com/xinshortlink/internal/pkg/middleware"
	"gitee.com/xinshortlink/internal/pkg/token"
	"gitee.com/xinshortlink/views"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"io"
	"net/http"
)

type Router struct {
	logger *zap.Logger
	Engine *gin.Engine
}

func NewRouter(conf *conf.Conf, logger *zap.Logger,
	resp *resp.Util,
	util *token.LoginAccountUtil,
	token *token.Token,
	accountApi *account.Api,
	groupApi *group.Api,
	linkApi *link.Api,
) *Router {
	serverConf := conf.Server
	gin.SetMode(serverConf.Mode) // 设置模式

	if serverConf.Mode == gin.ReleaseMode {
		gin.DefaultWriter = io.Discard // 设置 gin 默认日志输出目标为 io.Discard。等同于禁用 gin 日志
		// io.Discard 是一个 io.Writer 的特殊实现，仅仅接受写入数据。不做任何处理。
	}

	router := &Router{logger: logger, Engine: gin.New()}

	middlewares := make([]gin.HandlerFunc, 0)

	if serverConf.AccessLog {
		middlewares = append(middlewares, middleware.Logger(logger))
	}

	middlewares = append(middlewares, middleware.Recovery(logger, resp))

	router.Engine.Use(middlewares...)

	// 静态资源
	router.Engine.StaticFS("/views", http.FS(views.FS))

	// 404
	router.Engine.NoRoute(func(ctx *gin.Context) {
		resp.Resp(ctx, bizerr.ErrServerNotFound, nil)
	})

	// ping
	router.Engine.GET("/ping", func(c *gin.Context) {
		resp.Resp(c, nil, nil)
	})

	// 短链接跳转
	router.Engine.GET("/r/:shortId", func(ctx *gin.Context) {
		linkApi.Redirect(ctx)
	})

	apiGroup := router.Engine.Group("api")

	adminGroup := apiGroup.Group("/v1")

	adminGroup.Use(middleware.Auth(util, token, resp)) // token 校验

	{
		adminGroup.GET("/logout", func(ctx *gin.Context) {
			accountApi.Logout(ctx)
		})

		adminGroup.GET("/account/current", func(ctx *gin.Context) {
			accountApi.CurrentAccount(ctx)
		})

		adminGroup.PUT("/account/update", func(ctx *gin.Context) {
			accountApi.UpdateAccount(ctx)
		})

		adminGroup.GET("/group", func(ctx *gin.Context) {
			groupApi.Groups(ctx)
		})

		adminGroup.POST("/group/create", func(ctx *gin.Context) {
			groupApi.Create(ctx)
		})

		adminGroup.PUT("/group/update", func(ctx *gin.Context) {
			groupApi.Update(ctx)
		})

		adminGroup.DELETE("/group/del", func(ctx *gin.Context) {
			groupApi.Del(ctx)
		})

		adminGroup.GET("/link", func(ctx *gin.Context) {
			linkApi.Links(ctx)
		})

		adminGroup.POST("/link/create", func(ctx *gin.Context) {
			linkApi.Create(ctx)
		})
		adminGroup.POST("/link/create/batch", func(ctx *gin.Context) {
			linkApi.CreateBatch(ctx)
		})

		adminGroup.PUT("/link/status", func(ctx *gin.Context) {
			linkApi.UpdateStatus(ctx)
		})

		adminGroup.DELETE("/link/del", func(ctx *gin.Context) {
			linkApi.Del(ctx)
		})

		adminGroup.GET("/link/visit-record", func(ctx *gin.Context) {
			linkApi.GetVisitRecord(ctx)
		})
	}

	frontGroup := apiGroup.Group("/v1")
	{
		frontGroup.GET("/account/has", func(ctx *gin.Context) {
			accountApi.HasAccount(ctx)
		})
		frontGroup.POST("/account/register", func(ctx *gin.Context) {
			accountApi.Register(ctx)
		})
		frontGroup.POST("/login", func(ctx *gin.Context) {
			accountApi.Login(ctx)
		})
	}

	return router
}
